package com.ruoyi.redis.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.redis.entity.Shop;
import com.ruoyi.redis.mapper.ShopMapper;
import com.ruoyi.redis.service.IShopService;
import com.ruoyi.redis.util.RedisConstants;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {


    @Resource
    private StringRedisTemplate stringRedisTemplate;

	@Override
	public JSONObject queryById(Long id) {
		JSONObject returnJson = new JSONObject();
		 // 1从 redis中查询商铺缓存
		 String json = stringRedisTemplate.opsForValue().get(RedisConstants.CACHE_SHOP_KEY + id);
		// 2判断是否存在
		 if(StrUtil.isNotBlank(json)) {
			 //3.存在则直接返回
			 return JSONObject.parseObject(json);
		 }
		//4 判断命中是否是空值
		 if(json != null) {
			returnJson.put("error", "商铺id不存在!");
			return returnJson; 
		 }
		 //获取互斥锁
		 String lockkey = RedisConstants.LOCK_SHOP_KEY + id;
		 Shop shop = null;
		 try {
			boolean isLock = tryLock(lockkey);
			// 判断是否获取成功 
			if (!isLock) {
				// 获取锁失败,休眠
				Thread.sleep(50);
				return queryById(id);
			} 
			// 获取锁成功,根据id查询数据库
			shop = getById(id);
			// 模拟重建的延时
			Thread.sleep(200);		
			// 6 不存在,返回错误
			if(shop == null) {
				// 将空值写入redis.
				stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id, "",RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);
				 // 返回错误信息
				returnJson.put("error", "商铺id不存在!");
	            return returnJson;
			}
			// 7. 存在,写入
			stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id, JSONObject.toJSONString(shop), RedisConstants.CACHE_SHOP_TTL, TimeUnit.MINUTES);
			returnJson.put("data", JSONObject.toJSONString(shop));
			 
		} catch (Exception e) {
			 throw new RuntimeException(e);
		} finally {
			// 7.释放锁
            unlock(lockkey);
		}
		return returnJson;
	}

	@Override
	public JSONObject update(Shop shop) {

		return null;
	}

	@Override
	public JSONObject queryShopByType(Integer typeId, Integer current, Double x, Double y) {
		return null;
	}

	private boolean tryLock(String key) {
		Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10,  TimeUnit.SECONDS);
		return BooleanUtil.isTrue(flag);
	}
	
	private void unlock(String key) {
		stringRedisTemplate.delete(key);
	}
	
	
	
	
}
